/**
 * 防抖函数 - 用于限制函数在短时间内多次触发，只执行最后一次触发
 * @param {Function} fn 需要防抖的函数
 * @param {Number} delay 延迟时间，单位毫秒，默认300ms
 * @param {Boolean} immediate 是否立即执行，默认false
 * @return {Function} 防抖处理后的函数
 */
let timers = {};

export const debounce = (fn, delay = 300, immediate = false) => {
  // 为每个函数生成一个唯一标识
  const fnKey = fn.toString().slice(0, 100);
  
  return function(...args) {
    const context = this;
    
    // 是否应该立即执行的标志
    // 只有在immediate为true且计时器不存在时才立即执行
    const callNow = immediate && !timers[fnKey];
    
    // 如果已存在定时器，清除它，重置倒计时
    if (timers[fnKey]) {
      clearTimeout(timers[fnKey]);
    }
    
    // 立即执行模式下且条件满足时立即执行
    if (callNow) {
      fn.apply(context, args);
    }
    
    // 设置新的定时器
    // 无论是否立即执行模式，都需要设置定时器来清除状态
    timers[fnKey] = setTimeout(() => {
      // 非立即执行模式下，在延迟结束后执行函数
      if (!immediate) {
        fn.apply(context, args);
      }
      timers[fnKey] = null;
    }, delay);
  };
};

/**
 * 节流函数 - 用于限制函数在一定时间内最多执行一次
 * @param {Function} fn 需要节流的函数
 * @param {Number} delay 延迟时间，单位毫秒，默认300ms
 * @return {Function} 节流处理后的函数
 */
export const throttle = (fn, delay = 300) => {
  let lastTime = 0;
  
  return function(...args) {
    const context = this;
    const currentTime = Date.now();
    
    // 如果距离上次执行超过设定时间，则执行
    if (currentTime - lastTime > delay) {
      fn.apply(context, args);
      lastTime = currentTime;
    }
  };
};

/**
 * 创建一个防抖函数的高阶函数，在执行期间显示加载动画
 * @param {Function} fn 需要防抖的函数
 * @param {Object} options 配置选项
 * @param {Number} options.delay 延迟时间 默认300ms
 * @param {Boolean} options.immediate 是否立即执行 默认false
 * @param {Boolean} options.showLoading 是否显示加载提示 默认true
 * @param {String} options.loadingText 加载提示文本 默认"处理中..."
 * @return {Function} 防抖处理后的函数
 */
export const debounceWithLoading = (fn, options = {}) => {
  const { 
    delay = 300, 
    immediate = false, 
    showLoading = true,
    loadingText = "处理中..."
  } = options;
  
  // 防抖状态标记
  const fnKey = fn.toString().slice(0, 100);
  let isShowingLoading = false;
  
  return debounce(async function(...args) {
    const context = this;
    
    // 显示加载提示(仅当未显示时)
    if (showLoading && !isShowingLoading) {
      isShowingLoading = true;
      uni.showLoading({
        title: loadingText,
        mask: true
      });
    }
    
    try {
      // 执行原函数并返回结果
      return await fn.apply(context, args);
    } catch (error) {
      console.error('执行函数出错:', error);
      // 出错时显示提示
      uni.showToast({
        title: '操作失败',
        icon: 'none'
      });
      throw error; // 继续抛出错误，让上层处理
    } finally {
      // 隐藏加载提示
      if (showLoading && isShowingLoading) {
        uni.hideLoading();
        isShowingLoading = false;
      }
    }
  }, delay, immediate);
};

export default {
  debounce,
  throttle,
  debounceWithLoading
}; 